package com.jinmdz.fmis.api.admin.service;

import com.jinmdz.fmis.api.admin.model.organization.OrganizationIdData;
import com.jinmdz.fmis.api.admin.model.organization.OrganizationLoadData;
import com.jinmdz.fmis.api.admin.model.organization.OrganizationSaveData;
import com.jinmdz.fmis.api.admin.model.organization.OrganizationTreeItem;
import com.jinmdz.fmis.api.api.model.common.IdData;
import com.jinmdz.fmis.api.api.model.common.IdVersionData;
import com.jinmdz.fmis.api.api.service.DictionaryService;
import com.jinmdz.fmis.api.base.BaseService;
import com.jinmdz.fmis.api.model.config.dictionary.OperationLogCode;
import com.jinmdz.fmis.api.model.system.UserItem;
import com.jinmdz.fmis.api.wrapper.DictionaryWrapper;
import com.jinmdz.fmis.api.wrapper.OperationWrapper;
import com.jinmdz.fmis.common.ext.StringBuilderExt;
import com.jinmdz.fmis.common.util.BeanUtil;
import com.jinmdz.fmis.common.util.DataUtil;
import com.jinmdz.fmis.core.base.BaseResult;
import com.jinmdz.fmis.core.exception.ActionException;
import com.jinmdz.fmis.core.util.JacksonUtil;
import com.jinmdz.fmis.dao.admin.dao.OrganizationDao;
import com.jinmdz.fmis.dao.admin.model.organization.OrganizationEditItem;
import com.jinmdz.fmis.dao.admin.model.organization.OrganizationListItem;
import com.jinmdz.fmis.mapper.entity.OrganizationInstitutionEntity;
import com.jinmdz.fmis.mapper.mapper.OrganizationInstitutionMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;

/**
 * 组织机构Service
 *
 * @author LiCongLu
 * @date 2020-03-16 11:22
 */
@Service("organizationService")
public class OrganizationService extends BaseService {

    @Resource
    private OrganizationDao organizationDao;

    @Resource
    private DictionaryWrapper dictionaryWrapper;

    @Resource
    private OrganizationInstitutionMapper organizationInstitutionMapper;

    @Resource
    private OperationWrapper operationWrapper;

    @Resource
    private OperationLogCode operationLogCode;

    @Resource
    private DictionaryService dictionaryService;

    /**
     * 加载所有组织机构
     *
     * @param
     * @return
     * @author LiCongLu
     * @date 2020-03-16 11:11
     */
    public BaseResult loadOrganizationList() {
        ArrayList<OrganizationListItem> loadItems = organizationDao.listOrganizationList();
        // 设置字典文本
        dictionaryWrapper.resetDataText(loadItems);
        return successList(loadItems);
    }

    /**
     * 加载所有组织机构
     *
     * @param data 父类主键请求数据
     * @return
     * @author LiCongLu
     * @date 2020-03-16 11:11
     */
    public BaseResult<ArrayList<OrganizationTreeItem>> loadOrganizationTreeWithParentId(IdData data) {
        ArrayList<OrganizationListItem> listItems = organizationDao.listOrganizationListByParentId(data.getId());
        // 设置字典文本
        dictionaryWrapper.resetDataText(listItems);

        // 转化为树状机构集合
        ArrayList<OrganizationTreeItem> loadItems = new ArrayList<>();
        for (OrganizationListItem listItem : listItems) {
            OrganizationTreeItem loadItem = new OrganizationTreeItem();
            loadItem.setId(listItem.getId())
                    .setParentId(listItem.getParentId())
                    .setLabel(listItem.getOrganizationName());
            loadItems.add(loadItem);
        }
        return successList(loadItems);
    }

    /**
     * 加载所有组织机构
     *
     * @param data 父类主键请求数据
     * @return
     * @author LiCongLu
     * @date 2020-03-16 11:11
     */
    public BaseResult<ArrayList<OrganizationListItem>> loadOrganizationListWithParentId(IdData data) {
        ArrayList<OrganizationListItem> loadItems = organizationDao.listOrganizationListByParentId(data.getId());
        // 设置字典文本
        dictionaryWrapper.resetDataText(loadItems);
        return successList(loadItems);
    }

    /**
     * 加载组织机构
     *
     * @param data 请求主键
     * @return
     * @author LiCongLu
     * @date 2020-03-16 11:11
     */
    public BaseResult<OrganizationLoadData> loadOrganizationWithId(OrganizationIdData data) {
        // 加载数据
        OrganizationLoadData loadData = new OrganizationLoadData();

        // 加载业务数据
        if (DataUtil.valid(data.getId())) {
            Integer loadId = data.getId();
            // 查询业务信息
            OrganizationEditItem loadItem = organizationDao.getOrganizationEditById(loadId);
            if (DataUtil.isNull(loadItem) || DataUtil.isNull(loadItem.getId(), loadItem.getVersion())) {
                return failure("主键错误，不存在此组织机构信息");
            }

            // 复制返回数据
            loadData.setOrganization(BeanUtil.copy2Bean(loadItem, new OrganizationSaveData()));
        }

        // 加载字典数据
        loadData.setDicts(dictionaryService.loadDictionaryMap(data.getDictTypeCodes()));

        // 返回响应结果
        return successData(loadData);
    }

    /**
     * 保存组织机构信息
     *
     * @param userItem 当前帐号
     * @param data     请求数据
     * @return
     * @author LiCongLu
     * @date 2020-03-16 11:11
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult saveOrganization(UserItem userItem, OrganizationSaveData data) throws ActionException {
        Integer id = data.getId();
        // 主键不为空
        if (DataUtil.valid(id)) {
            updateOrganization(userItem, data);
        } else {
            insertOrganization(userItem, data);
        }
        return success("保存成功");
    }

    /**
     * 插入组织机构信息
     *
     * @param userItem 当前帐号
     * @param data     请求数据
     * @return
     * @author LiCongLu
     * @date 2020-03-16 11:11
     */
    private Integer insertOrganization(UserItem userItem, OrganizationSaveData data) throws ActionException {
        // 创建实体
        OrganizationInstitutionEntity entity = getEntity(userItem, OrganizationInstitutionEntity.class);

        // 覆盖数据
        BeanUtil.copy2Bean(data, entity);

        // 对组织机构进行判断处理
        checkOrganizationValue(entity);

        // 新增组织机构
        organizationInstitutionMapper.insertOrganizationInstitution(entity);
        // 判断保存组织机构结果
        if (DataUtil.invalid(entity.getId())) {
            throw exception("保存组织机构信息失败");
        }

        // 添加操作日志
        saveOrganizationLog(userItem, operationLogCode.getInsert(), data, null, entity);
        return entity.getId();
    }

    /**
     * 验证处理组织机构
     *
     * @param entity 组织机构
     * @return
     * @author LiCongLu
     * @date 2020-03-16 11:11
     */
    private void checkOrganizationValue(OrganizationInstitutionEntity entity) throws ActionException {

        // 判断父组织结构主键
        if (DataUtil.isNull(entity.getParentId())) {
            entity.setParentId(0).setParentName("");
        }

        // 判断父组织机构名称
        if (DataUtil.invalid(entity.getParentName())) {
            entity.setParentName("");
        }

        // 判断禁用状态
        if (DataUtil.isNull(entity.getDisableState())) {
            entity.setDisableState(0);
        }

        // 判断排序值
        if (DataUtil.isNull(entity.getSort())) {
            entity.setSort(0);
        }

        // 判断组织机构编码
        if (DataUtil.isNull(entity.getOrganizationCode())) {
            entity.setOrganizationCode("");
        }

        // 判断组织机构编码的重复性
        if (DataUtil.valid(entity.getOrganizationCode())) {
            Integer organizationCodeId = organizationDao.getOrganizationIdByOrganizationCode(entity.getId(), entity.getOrganizationCode());
            if (DataUtil.valid(organizationCodeId)) {
                throw exception("存在重复的组织机构编码");
            }
        }

        // 判断组织机构名称的重复性
        Integer organizationNameId = organizationDao.getOrganizationIdByOrganizationName(entity.getId(), entity.getOrganizationName(), entity.getParentId());
        if (DataUtil.valid(organizationNameId)) {
            throw exception("存在重复的组织机构名称");
        }
    }

    /**
     * 添加修改组织机构记录
     *
     * @param userItem    当前帐号
     * @param logTypeCode 操作日志值
     * @param data        请求数据
     * @param oldValue    旧数据
     * @param entity      保存实体
     * @return
     * @author LiCongLu
     * @date 2020-03-16 11:11
     */
    private void saveOrganizationLog(UserItem userItem, Integer logTypeCode, OrganizationSaveData data, String oldValue, OrganizationInstitutionEntity entity) throws ActionException {
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("保存组织机构，父组织机构[{0}]，组织机构编码[{1}]，组织机构名称[{2}]，组织机构组织简称[{3}]，操作人员[{4}]"
                , data.getParentCode(), entity.getOrganizationCode(), entity.getOrganizationName()
                , entity.getOrganizationAbbreviation(), userItem.getFullName());

        // 添加日志
        operationWrapper.operationLog(userItem, logTypeCode, builder.toString(), JacksonUtil.obj2Json(data), oldValue, JacksonUtil.obj2Json(entity));
    }

    /**
     * 更新组织机构
     *
     * @param userItem 当前帐号
     * @param data     请求数据
     * @return
     * @author LiCongLu
     * @date 2020-03-16 11:11
     */
    private void updateOrganization(UserItem userItem, OrganizationSaveData data) throws ActionException {
        // 验证主键和数据版本是否存在
        if (DataUtil.isNull(data.getId(), data.getVersion())) {
            throw exception("请求组织机构主键与组织机构版本号不能为空");
        }

        // 通过主键获取组织机构
        OrganizationInstitutionEntity entity = organizationInstitutionMapper.getOrganizationInstitutionById(data.getId());
        if (DataUtil.isNull(entity) || DataUtil.isNull(entity.getId(), entity.getVersion())) {
            throw exception("组织机构主键错误，不存在此组织机构");
        }

        // 验证组织机构信息版本
        if (!DataUtil.equals(data.getVersion(), entity.getVersion())) {
            throw exception(versionError("组织机构"));
        }

        // 记录旧数据
        String oldValue = JacksonUtil.obj2Json(entity);

        // 覆盖数据
        BeanUtil.copy2Bean(data, entity);

        // 对组织机构进行判断处理
        checkOrganizationValue(entity);

        // 更新组织机构
        organizationInstitutionMapper.updateOrganizationInstitution(entity);

        // 添加操作日志
        saveOrganizationLog(userItem, operationLogCode.getUpdate(), data, oldValue, entity);
    }

    /**
     * 删除指定id的组织机构记录
     *
     * @param userItem 当前帐号
     * @param data     主键和版本号
     * @return
     * @author LiCongLu
     * @date 2020-03-16 11:11
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult deleteOrganizationWithId(UserItem userItem, ArrayList<IdVersionData> data) throws ActionException {
        // 判断删除主键集合是否存在
        if (DataUtil.invalid(data)) {
            throw exception("不存在要删除的组织机构");
        }

        // 验证主键是否重复
        if (data.size() != getRepeatIdSize(data)) {
            throw exception("组织机构主键存在重复");
        }

        // 记录组织机构集合
        ArrayList<OrganizationEditItem> loadItems = new ArrayList<>();

        // 进行遍历删除信息
        for (IdVersionData idData : data) {
            // 通过主键查询组织机构
            OrganizationEditItem loadItem = organizationDao.getOrganizationEditById(idData.getId());
            if (DataUtil.isNull(loadItem) || DataUtil.isNull(loadItem.getId(), loadItem.getVersion())) {
                throw exception("主键错误，不存在此组织机构");
            }

            // 验证组织机构版本
            if (!DataUtil.equals(loadItem.getVersion(), idData.getVersion())) {
                throw exception(versionError("组织机构"));
            }

            // 判断其子组织机构的个数
            Integer organizationCount = organizationDao.getOrganizationCountByParentId(loadItem.getId());
            if (DataUtil.valid(organizationCount)) {
                throw exception("存在子组织机构无法删除");
            }

            // 删除组织机构
            organizationInstitutionMapper.deletedForOrganizationInstitution(loadItem.getId(), userItem.getId(), loadItem.getVersion());
            // 记录组织机构
            loadItems.add(loadItem);
        }

        // 添加操作日志信息
        deleteOrganizationLog(userItem, operationLogCode.getDelete(), data, loadItems);

        return success("删除成功");
    }

    /**
     * 添加修改记录
     *
     * @param userItem    当前帐号
     * @param logTypeCode 操作日志值
     * @param data        请求数据
     * @param loadItems   删除信息实体
     * @return
     * @author LiCongLu
     * @date 2020-03-16 11:11
     */
    private void deleteOrganizationLog(UserItem userItem, Integer logTypeCode, ArrayList<IdVersionData> data, ArrayList<OrganizationEditItem> loadItems) throws ActionException {
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("删除组织机构，操作人员[{1}]", userItem.getFullName());
        // 添加日志
        operationWrapper.operationLog(userItem, logTypeCode, builder.toString(), JacksonUtil.obj2Json(data), JacksonUtil.obj2Json(loadItems), null);
    }
}
